package lucava.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;

import lucava.importer.java.XmlImporter;
import lucava.importer.uspeed.FileImporter;
import lucava.metamodel.dot.DotGraph;
import lucava.metamodel.dot.visitor.DotFileGenerator;
import lucava.metamodel.java.MetaModel;
import lucava.metamodel.java.visitor.DotMetaModelGenerator;
import lucava.metamodel.java.visitor.JavaFileGenerator;
import lucava.metamodel.uspeed.UspeedDocument;
import lucava.metamodel.uspeed.visitor.XmlVisitor;
import lucava.util.FileBuffer;
import lucava.util.FileBufferWriter;
import lucava.util.GraphVizGenerator;
import lucava.widget.uspeed.UspeedEditor;

import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

public class TransformatorGUI {

	protected JFrame mFrame = new JFrame("PlantecTransformator");
	protected UspeedEditor mEditorPanel = new UspeedEditor();
	protected JPanel mGraphPanel = new JPanel();

	protected String mCurrentImageFilePath = "";

	public TransformatorGUI() {
		this.createGUI();
	}

	public void launch() {

		SwingUtilities.invokeLater(new Runnable() {
			public void run() {

				// Centrage de la fenêtre au milieu de l'écran.
				JFrame frame = TransformatorGUI.this.mFrame;
				Dimension screenSize = java.awt.Toolkit.getDefaultToolkit()
						.getScreenSize();

				refreshIHMWith(mCurrentImageFilePath);

				frame.setLocation((screenSize.width - frame.getWidth()) / 2,
						(screenSize.height - frame.getHeight()) / 2);

				TransformatorGUI.this.mFrame.setVisible(true);

			}
		});

	}

	protected void refreshIHMWith(String aFileName) {
		this.clearImageView();
		mGraphPanel.add(new ImagePanel(aFileName));
		mGraphPanel.repaint();
		this.mFrame.pack();
	}

	protected void clearImageView() {
		this.mGraphPanel.removeAll();
	}

	private void createGUI() {

		// Création de la fenetre principale
		mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mFrame.setBackground(Color.lightGray);

		Dimension screenSize = java.awt.Toolkit.getDefaultToolkit()
				.getScreenSize();
		Dimension minSize = new Dimension(screenSize.width * 2 / 3,
				screenSize.height * 4 / 5);

		mFrame.setMinimumSize(minSize);

		// Création de la partie avec les boutons
		JPanel buttonsPanel = this.getButtonsPanel();
		mFrame.add(buttonsPanel, BorderLayout.NORTH);

		// Création de la partie Editeur
		JScrollPane editorScrollPane = new JScrollPane();

		editorScrollPane.getViewport().add(mEditorPanel);
		editorScrollPane.setBorder(BorderFactory.createLineBorder(Color.green,
				2));

		// Création de la partie Graphe
		JScrollPane graphScrollPane = new JScrollPane();
		graphScrollPane.getViewport().add(mGraphPanel);
		graphScrollPane
				.setBorder(BorderFactory.createLineBorder(Color.blue, 2));

		JSplitPane transformateurSplitPaneArea = new JSplitPane(
				JSplitPane.HORIZONTAL_SPLIT, editorScrollPane, graphScrollPane);

		mFrame.add(transformateurSplitPaneArea, BorderLayout.CENTER);
		transformateurSplitPaneArea.setDividerLocation(0.5);

		this.addMenu();
	}

	public JPanel getButtonsPanel() {

		JPanel buttonsPanel = new JPanel();
		JButton generateAllButton = new JButton("Generate ALL!");
		generateAllButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				TransformatorGUI.this.generateAll();
			}
		});

		JButton genXmlButton = new JButton("XML");
		genXmlButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				TransformatorGUI.this.generateXml();
			}
		});

		JButton genJavaButton = new JButton("JAVA");
		genJavaButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				TransformatorGUI.this.generateJava();
			}
		});

		JButton genDotButton = new JButton("DOT");
		genDotButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				TransformatorGUI.this.generateDot();
			}
		});

		JButton genGrapheButton = new JButton("Graphe");
		genGrapheButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				TransformatorGUI.this.generateGraphe();
			}
		});

		buttonsPanel.add(generateAllButton);
		buttonsPanel.add(genXmlButton);
		buttonsPanel.add(genJavaButton);
		buttonsPanel.add(genDotButton);
		buttonsPanel.add(genGrapheButton);

		return buttonsPanel;
	}

	public void addMenu() {
		JMenuBar menubar = new JMenuBar();

		JMenu file = new JMenu("File");

		JMenuItem newMenuItem = new JMenuItem("New file");
		newMenuItem.setToolTipText("Édite un nouveau fichier");
		newMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.createNewFile();
			}
		});
		file.add(newMenuItem);

		JMenuItem loadMenuItem = new JMenuItem("Load file");
		loadMenuItem.setToolTipText("Charge un fichier");
		loadMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.openUspeedFile();
			}
		});
		file.add(loadMenuItem);

		JMenuItem saveMenuItem = new JMenuItem("Save file");
		saveMenuItem.setToolTipText("Sauvegarde le fichier");
		saveMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.saveFile();
			}
		});
		file.add(saveMenuItem);

		JMenuItem exitMenuItem = new JMenuItem("Exit");
		exitMenuItem.setToolTipText("Quitte l'application");
		exitMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				System.exit(0);
			}
		});

		file.add(exitMenuItem);
		menubar.add(file);

		JMenu generate = new JMenu("Generate");

		JMenuItem genAllMenuItem = new JMenuItem("ALL!");
		genAllMenuItem.setToolTipText("Génère tout!");
		genAllMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.generateAll();
			}
		});
		generate.add(genAllMenuItem);

		JMenuItem genXmlMenuItem = new JMenuItem("XML");
		genXmlMenuItem.setToolTipText("Génère le XML");
		genXmlMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.generateXml();
			}
		});
		generate.add(genXmlMenuItem);

		JMenuItem genJavaMenuItem = new JMenuItem("JAVA");
		genJavaMenuItem.setToolTipText("Génère les classes Java");
		genJavaMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.generateJava();
			}
		});
		generate.add(genJavaMenuItem);

		JMenuItem genDotMenuItem = new JMenuItem("DOT");
		genDotMenuItem.setToolTipText("Génère le .dot");
		genDotMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.generateDot();
			}
		});
		generate.add(genDotMenuItem);

		JMenuItem genGrapheMenuItem = new JMenuItem("Graphe");
		genGrapheMenuItem.setToolTipText("Génère le graphe (.png)");
		genGrapheMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.generateGraphe();
			}
		});
		generate.add(genGrapheMenuItem);

		JMenu credits = new JMenu("?");

		JMenuItem creditMenuItem = new JMenuItem("Credits");
		creditMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				TransformatorGUI.this.showCredits();
			}
		});
		credits.add(creditMenuItem);

		menubar.add(file);
		menubar.add(generate);
		menubar.add(credits);

		this.mFrame.setJMenuBar(menubar);
	}

	protected void generateAll() {

		String folderPath = this.getFolderPath();
		String folderPathSlash = folderPath
				+ System.getProperty("file.separator");

		try {
			FileImporter parser = new FileImporter();
			UspeedDocument document;

			document = parser.loadContent(this.mEditorPanel.getText());

			XmlVisitor visitor = new XmlVisitor();
			document.accept(visitor);

			visitor.export(folderPathSlash + "test.xml");

			XmlImporter importer = new XmlImporter();
			MetaModel model = importer.load(folderPathSlash + "test.xml");

			DotMetaModelGenerator dotGen = new DotMetaModelGenerator();
			model.accept(dotGen);

			DotGraph graph = dotGen.getGeneratedGraph();

			DotFileGenerator generator = new DotFileGenerator(folderPathSlash);
			graph.accept(generator);
			FileBuffer generatedDot = generator.getGeneratedFile();
			FileBufferWriter.generateFileFor(generatedDot);

			GraphVizGenerator.generatePNGFromFile(graph.getName() + ".dot",
					folderPathSlash + "uspeedMetaModel.png");

			JavaFileGenerator codegen = new JavaFileGenerator(folderPath);
			model.accept(codegen);

			FileBufferWriter.generateFileFor(codegen.getGeneratedFiles());

			// Chargement de l'image
			this.refreshIHMWith(folderPathSlash + "uspeedMetaModel.png");

			JOptionPane.showMessageDialog(null, "Génération réussie!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void generateXml() {

		String folderPath = this.getFolderPath();
		String folderPathSlash = folderPath
				+ System.getProperty("file.separator");

		try {
			FileImporter parser = new FileImporter();
			UspeedDocument document;

			document = parser.loadContent(this.mEditorPanel.getText());

			XmlVisitor visitor = new XmlVisitor();
			document.accept(visitor);

			visitor.export(folderPathSlash + "test.xml");

			JOptionPane.showMessageDialog(null, "Génération réussie!");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	protected void generateJava() {
		String folderPath = this.getFolderPath();

		try {
			FileImporter parser = new FileImporter();
			UspeedDocument document;

			document = parser.loadContent(this.mEditorPanel.getText());

			XmlVisitor visitor = new XmlVisitor();
			document.accept(visitor);

			Document jDomDoc = visitor.buildDocument();

			XMLOutputter outputter = new XMLOutputter();

			XmlImporter importer = new XmlImporter();
			MetaModel model = importer.loadContent(outputter
					.outputString(jDomDoc));

			JavaFileGenerator codegen = new JavaFileGenerator(folderPath);
			model.accept(codegen);

			FileBufferWriter.generateFileFor(codegen.getGeneratedFiles());

			JOptionPane.showMessageDialog(null, "Génération réussie!");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	protected void generateDot() {

		String folderPath = this.getFolderPath();
		String folderPathSlash = folderPath
				+ System.getProperty("file.separator");

		try {
			FileImporter parser = new FileImporter();
			UspeedDocument document;

			document = parser.loadContent(this.mEditorPanel.getText());

			XmlVisitor visitor = new XmlVisitor();
			document.accept(visitor);

			Document jDomDoc = visitor.buildDocument();

			XMLOutputter outputter = new XMLOutputter();

			XmlImporter importer = new XmlImporter();
			MetaModel model = importer.loadContent(outputter
					.outputString(jDomDoc));

			DotMetaModelGenerator dotGen = new DotMetaModelGenerator();
			model.accept(dotGen);

			DotGraph graph = dotGen.getGeneratedGraph();

			DotFileGenerator generator = new DotFileGenerator(folderPathSlash);
			graph.accept(generator);
			FileBuffer generatedDot = generator.getGeneratedFile();
			FileBufferWriter.generateFileFor(generatedDot);

			JOptionPane.showMessageDialog(null, "Génération réussie!");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	protected void generateGraphe() {

		String folderPath = this.getFolderPath();
		String folderPathSlash = folderPath
				+ System.getProperty("file.separator");

		try {
			FileImporter parser = new FileImporter();
			UspeedDocument document;

			document = parser.loadContent(this.mEditorPanel.getText());

			XmlVisitor visitor = new XmlVisitor();
			document.accept(visitor);

			Document jDomDoc = visitor.buildDocument();

			XMLOutputter outputter = new XMLOutputter();

			XmlImporter importer = new XmlImporter();
			MetaModel model = importer.loadContent(outputter
					.outputString(jDomDoc));

			DotMetaModelGenerator dotGen = new DotMetaModelGenerator();
			model.accept(dotGen);

			DotGraph graph = dotGen.getGeneratedGraph();

			DotFileGenerator generator = new DotFileGenerator(folderPathSlash);
			graph.accept(generator);
			FileBuffer generatedDot = generator.getGeneratedFile();

			GraphVizGenerator.generatePNGFromString(generatedDot.getContent(),
					folderPathSlash + "uspeedMetaModel.png");

			// Chargement de l'image
			this.refreshIHMWith(folderPathSlash + "uspeedMetaModel.png");

			JOptionPane.showMessageDialog(null, "Génération réussie!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	protected void createNewFile() {
		this.mEditorPanel.setText("");
	}

	protected String getFilePath() {
		JFileChooser fileChooser = new JFileChooser();
		String file = "";
		if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {

			file = fileChooser.getSelectedFile().getAbsolutePath();
		}
		return file;

	}

	protected void openUspeedFile() {
		JFileChooser fileChooser = new JFileChooser();
		File file = null;
		boolean fileOpened = false;
		if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {

			file = fileChooser.getSelectedFile();
			fileOpened = true;
		}

		// Si le fichier a été ouvert
		if (fileOpened) {
			this.loadFile(file);
		}

	}

	protected void loadFile(File aFile) {
		StringBuffer contentBuffer = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(aFile));
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(
					null,
					"Erreur lors de l'ouverture du fichier '"
							+ aFile.getAbsolutePath() + "'");
		}

		try {
			try {
				String line;

				line = reader.readLine();

				while ((line = reader.readLine()) != null) {
					contentBuffer.append(line);
					contentBuffer.append(System.getProperty("line.separator"));
				}

			} finally {
				reader.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			JOptionPane.showMessageDialog(null, "Une erreur est survenue!");
		}

		this.mEditorPanel.setText(contentBuffer.toString());
	}

	protected void saveFile() {
		String filePath = this.getFilePath();
		FileBuffer fileBuffer = new FileBuffer(filePath);
		fileBuffer.print(mEditorPanel.getText());

		FileBufferWriter.generateFileFor(fileBuffer);
	}

	public String getFolderPath() {

		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		String folder = "";
		if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {

			folder = fileChooser.getSelectedFile().getAbsolutePath();
		}

		return folder;
	}

	public void showCredits() {
		JOptionPane.showMessageDialog(null,
				"CAVARLÉ Glenn\nLUCAS Stéphane\n		M2-TIIL 2013");
	}

	protected Document parseUspeed(String uspeed) {
		Document doc = new Document();
		FileImporter importer = new FileImporter();
		try {
			XmlVisitor visitor = new XmlVisitor();
			importer.loadContent(uspeed).accept(visitor);
			doc = visitor.buildDocument();

		} catch (FileNotFoundException ex) {
			Logger.getLogger(TransformatorGUI.class.getName()).log(
					Level.SEVERE, null, ex);
		} catch (IOException ex) {
			Logger.getLogger(TransformatorGUI.class.getName()).log(
					Level.SEVERE, null, ex);
		}
		return doc;
	}

	protected String generateXmlContent() throws FileNotFoundException,
			IOException {
		String fileName = this.getFilePath();

		FileImporter fileImporter = new FileImporter();
		UspeedDocument uspeedDoc = fileImporter.load(fileName);

		XmlVisitor visitor = new XmlVisitor();
		uspeedDoc.accept(visitor);

		Document jDomDoc = visitor.buildDocument();

		XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());

		return outputter.outputString(jDomDoc);
	}

	protected List<FileBuffer> generateJavaClassesFromXmlDocument(
			Document xmlDoc) {
		String folderPath = this.getFolderPath();
		List<FileBuffer> generatedFiles = new ArrayList<FileBuffer>();

		XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
		XmlImporter importer = new XmlImporter();
		try {
			MetaModel model = importer.loadContent(outputter
					.outputString(xmlDoc));

			JavaFileGenerator javaGenerator = new JavaFileGenerator(folderPath);
			model.accept(javaGenerator);

			generatedFiles = javaGenerator.getGeneratedFiles();

		} catch (JDOMException ex) {
			Logger.getLogger(TransformatorGUI.class.getName()).log(
					Level.SEVERE, null, ex);
		} catch (IOException ex) {
			Logger.getLogger(TransformatorGUI.class.getName()).log(
					Level.SEVERE, null, ex);
		}

		return generatedFiles;
	}

	protected FileBuffer generateDotFileFromDotGraph(DotGraph aGotGraph) {
		DotFileGenerator dotfileGenerator = new DotFileGenerator();
		aGotGraph.accept(dotfileGenerator);

		return dotfileGenerator.getGeneratedFile();
	}

	protected DotGraph generateDotGraphFromMetaModel(MetaModel aMetaModel) {
		DotMetaModelGenerator dotGenenerator = new DotMetaModelGenerator();
		aMetaModel.accept(dotGenenerator);

		return dotGenenerator.getGeneratedGraph();
	}
}
